package edu.cs3240.visual;

import javax.swing.JFrame;

import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.util.mxMorphing;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxEventObject;
import com.mxgraph.util.mxEventSource.mxIEventListener;
import com.mxgraph.view.mxGraph;

import edu.cs3240.nfa.Part;
import edu.cs3240.nfa.State;
import edu.cs3240.nfa.Transition;

public class GraphVisualization extends JFrame
{
	private static final long serialVersionUID = -2707712944901661771L;

	public GraphVisualization(Part part)
	{
		super("Hello, World!");

		mxGraph graph = new mxGraph();
		
		graph.setAutoSizeCells(true);

		graph.getModel().beginUpdate();
		try
		{
			createGraph(graph, part.getStart(), null, null, null);
		}
		finally
		{
			graph.getModel().endUpdate();
		}

		mxGraphComponent graphComponent = new mxGraphComponent(graph);
		layoutGraph(graph, graphComponent);
		getContentPane().add(graphComponent);
	}
	
	private void createGraph(mxGraph graph, State state, State parent, Transition incoming, Object parentNode)
	{
		//create this node
		Object startNode = graph.insertVertex(null, null, "",0,0,10,10);
		
		//add edge from parent if necessary
		if(parent != null)
		{
			graph.insertEdge(null, null, incoming.toString() , parentNode, startNode);
		}

		//recurse for children
		if(state != null)
		{
			for(Transition t : state.getTransitions())
			{
				createGraph(graph, t.getTo(), state, t, startNode);
			}	
		}
	}
	
	private void layoutGraph(final mxGraph graph, mxGraphComponent graphComponent)
	{

	    mxHierarchicalLayout layout = new mxHierarchicalLayout(graph);
	    Object cell = graph.getSelectionCell();
	    if (cell == null || graph.getModel().getChildCount(cell) == 0)
	    {
	        cell = graph.getDefaultParent();
	    }

	    /*layout.setRadiusScaleFactor(1.0);
	    layout.setApproxNodeDimensions(false);*/
	    //layout.setEdgeCrossingCostFactor(8000);
	    /*layout.setNodeDistributionCostFactor(
	            layout.getNodeDistributionCostFactor() * 5);*/
	    /*layout.setEdgeDistanceCostFactor(layout.getEdgeDistanceCostFactor() * 5);
	    layout.setEdgeLengthCostFactor(layout.getEdgeLengthCostFactor() / 10);*/

	    graph.getModel().beginUpdate();

	        try
	        {
	            layout.execute(cell);
	        } finally
	        {
	            mxMorphing morph = new mxMorphing(graphComponent,
	                    20,
	                    1.2,
	                    20);
	            morph.addListener(mxEvent.DONE,
	                    new mxIEventListener()
	                    {

	                        @Override
	                        public void invoke(Object sender,
	                                mxEventObject evt)
	                        {
	                            graph.getModel().endUpdate();
	                        }
	                    });
	            morph.startAnimation();
	        }

	}
}
